#include "ibas_in.h"

#define MAXSIZE_INOTIFY_BUFFER		1024*1024+1

void app_signal_handler( int signo , siginfo_t *info , void *ptr )
{
	pid_t		pid ;
	char		*p = NULL ;
	
	signal( signo , SIG_DFL );
	pid = getpid() ;
	
	p = DumpFuncStack( g_funcstack ) ;
	FATALLOGG( "*** PROCESS %d RECEIVED SIGNAL %s ***\n"
		"============================================================\n"
		"%s"
		"============================================================\n"
		, pid , strsignal(signo)
		, p );
	free( p );
	
	if( signo == SIGALRM )
		exit(9);
	
	kill( pid , signo );
	
	return;
}

#if 0
int OnProcessAliveReport( struct IbasEnv *p_env )
{
	char			*uri = NULL ;
	
	ibp_alive_report_reqmsg	ibp_alive_report ;
	char			*reqmsg = NULL ;
	int			reqmsg_len ;
	
	struct HttpBuffer	*req_buf = NULL ;
	struct HttpBuffer	*rsp_buf = NULL ;
	
	int			nret = 0 ;
	
	if( p_env->report_session.netaddr.sock == -1 )
	{
		p_env->report_session.netaddr.sock = socket( AF_INET , SOCK_STREAM , IPPROTO_TCP ) ;
		if( p_env->report_session.netaddr.sock == -1 )
		{
			ERRORLOGSG( "socket failed , errno[%d]" , errno );
			return HTTP_SERVICE_UNAVAILABLE;
		}
		
		SetHttpNodelay( p_env->report_session.netaddr.sock , 1 );
		
		SETNETADDRESS( p_env->report_session.netaddr )
		nret = connect( p_env->report_session.netaddr.sock , (struct sockaddr *) & (p_env->report_session.netaddr.addr) , sizeof(struct sockaddr) ) ;
		if( nret == -1 )
		{
			ERRORLOGSG( "connect[%s:%d] failed , errno[%d]" , p_env->report_session.netaddr.ip , p_env->report_session.netaddr.port , errno );
			close( p_env->report_session.netaddr.sock ); p_env->report_session.netaddr.sock = -1 ;
			return HTTP_SERVICE_UNAVAILABLE;
		}
		else
		{
			INFOLOGSG( "connect[%s:%d] ok" , p_env->report_session.netaddr.ip , p_env->report_session.netaddr.port );
		}
		
		uri = IBP_URI_ALIVE_REPORT_FIRST ;
	}
	else
	{
		uri = IBP_URI_ALIVE_REPORT ;
	}
	
	ResetHttpEnv( p_env->report_session.http );
	ResetHttpSecureEnv( );
	
	memset( & ibp_alive_report , 0x00 , sizeof(ibp_alive_report_reqmsg) );
	strcpy( ibp_alive_report.node , p_env->node );
	strcpy( ibp_alive_report.ip , p_env->ibas_conf.ibas.server.ip );
	ibp_alive_report.port = p_env->ibas_conf.ibas.server.port ;
	nret = DSCSERIALIZE_JSON_DUP_ibp_alive_report_reqmsg( & ibp_alive_report , "GB18030" , & reqmsg , NULL , & reqmsg_len ) ;
	if( nret )
	{
		ERRORLOGSG( "DSCSERIALIZE_JSON_DUP_ibp_alive_report_reqmsg failed[%d] , errno[%d]" , nret , errno );
		return HTTP_INTERNAL_SERVER_ERROR;
	}
	
	req_buf = GetHttpRequestBuffer( p_env->report_session.http ) ;
	nret = StrcpyfHttpBuffer( req_buf , "POST %s HTTP/1.0" HTTP_RETURN_NEWLINE
					"Content-length: %d" HTTP_RETURN_NEWLINE
					"Connection: keep-alive" HTTP_RETURN_NEWLINE
					HTTP_RETURN_NEWLINE
					"%s"
					, uri
					, reqmsg_len
					, reqmsg );
	if( nret )
	{
		ERRORLOGSG( "StrcpyfHttpBuffer failed[%d]" , nret );
		free( reqmsg );
		close( p_env->report_session.netaddr.sock ); p_env->report_session.netaddr.sock = -1 ;
		return HTTP_INTERNAL_SERVER_ERROR;
	}
	
	free( reqmsg );
	
	DEBUGHEXLOGSG( GetHttpBufferBase(req_buf,NULL) , GetHttpBufferLength(req_buf) , "RequestBuffer" );
	
	SetHttpTimeout( p_env->report_session.http , 60 );
	
	nret = SendHttpRequest( p_env->report_session.netaddr.sock , NULL , p_env->report_session.http ) ;
	if( nret )
	{
		ERRORLOGSG( "SendHttpRequest failed[%d]" , nret );
		close( p_env->report_session.netaddr.sock ); p_env->report_session.netaddr.sock = -1 ;
		return HTTP_SERVICE_UNAVAILABLE;
	}
	
	nret = ReceiveHttpResponse( p_env->report_session.netaddr.sock , NULL , p_env->report_session.http ) ;
	if( nret )
	{
		ERRORLOGSG( "ReceiveHttpResponse failed[%d]" , nret );
		close( p_env->report_session.netaddr.sock ); p_env->report_session.netaddr.sock = -1 ;
		return HTTP_SERVICE_UNAVAILABLE;
	}
	
	rsp_buf = GetHttpResponseBuffer( p_env->report_session.http ) ;
	DEBUGHEXLOGSG( GetHttpBufferBase(rsp_buf,NULL) , GetHttpBufferLength(rsp_buf) , "ResponseBuffer" );
	
	return GetHttpStatusCode(p_env->report_session.http);
}
#endif

int OnProcessSoCacheChanged( struct IbasEnv *p_env )
{
	fd_set			read_fds ;
	struct timeval		tv ;
	
	static char		*inotify_buffer = NULL ;
	int			nread ;
	int			npro ;
	struct inotify_event	*p_event = NULL ;
	struct SoFile		so_file ;
	struct SoFile		*p_so_file = NULL ;
	
	int			nret = 0 ;
	
	if( inotify_buffer == NULL )
	{
		inotify_buffer = (char*)malloc( MAXSIZE_INOTIFY_BUFFER ) ;
		if( inotify_buffer == NULL )
		{
			FATALLOGSG( "malloc failed , errno[%d]" , errno );
			return HTTP_INTERNAL_SERVER_ERROR;
		}
	}
	
	while(1)
	{
		FD_ZERO( & read_fds );
		FD_SET( p_env->inotify_fd , & read_fds );
		memset( & tv , 0x00 , sizeof(struct timeval) );
		nret = select( p_env->inotify_fd+1 , & read_fds , NULL , NULL , & tv ) ;
		if( nret == -1 )
		{
			FATALLOGSG( "select failed , errno[%d]" , errno );
			return HTTP_INTERNAL_SERVER_ERROR;
		}
		else if( nret == 0 )
		{
			break;
		}
		
		memset( inotify_buffer , 0x00 , MAXSIZE_INOTIFY_BUFFER );
		nread = read( p_env->inotify_fd , inotify_buffer , MAXSIZE_INOTIFY_BUFFER-1 ) ;
		if( nread <= 0 )
		{
			FATALLOGSG( "read failed[%d] , errno[%d]" , nread , ERRNO );
			return HTTP_INTERNAL_SERVER_ERROR;
		}
		else
		{
			DEBUGLOGSG( "read ok , [%d]bytes" , nread );
		}
		
		npro = 0 ;
		while( npro < nread )
		{
			p_event = (struct inotify_event *)(inotify_buffer+npro) ;
			INFOLOGSG( "inotify event wd[%d] mask[0x%X] len[%d] name[%.*s]" , p_event->wd , p_event->mask , p_event->len , p_event->len , p_event->name );
			
			memset( & so_file , 0x00 , sizeof(struct SoFile) );
			so_file.file_wd = p_event->wd ;
			p_so_file = QuerySoFileWdTreeNode( p_env , & so_file ) ;
			if( p_so_file )
			{
				INFOLOGSG( "inotify_rm_watch[%d]" , p_event->wd );
				inotify_rm_watch( p_env->inotify_fd , p_so_file->file_wd );
				
				INFOLOGSG( "RemoveSoBinTreeNode[%s]" , p_so_file->so_pathfilename );
				UnlinkSoBinTreeNode( p_env , p_so_file );
				INFOLOGSG( "RemoveSoCallCountTreeNode[%s]" , p_so_file->so_pathfilename );
				UnlinkSoCallCountTreeNode( p_env , p_so_file );
				INFOLOGSG( "RemoveSoFileWdTreeNode[%s]" , p_so_file->so_pathfilename );
				UnlinkSoFileWdTreeNode( p_env , p_so_file );
				
				dlclose( p_so_file->so_handle );
				free( p_so_file );
				
				p_env->so_cache_count--;
			}
			
			npro += sizeof(struct inotify_event) + p_event->len ;
		}
	}
	
	return HTTP_OK;
}

static int CheckHeaderNode( struct IbasEnv *p_env )
{
	char			*HTTPHEADER_Ibp_Server_Node = NULL ;
	int			HTTPHEADERLEN_Ibp_Server_Node ;
	int			node_len ;
	char			*p_node = NULL ;
	
	char			*HTTPHEADER_Ibp_Client_Node = NULL ;
	int			HTTPHEADERLEN_Ibp_Client_Node ;
	char			node[ IBP_MAXLEN_NODE + 1 ] ;
	
	HTTPHEADER_Ibp_Server_Node = QueryHttpHeaderPtr( p_env->accepted_session.http , IBP_HTTPHEADER_IBP_SERVER_NODE , & HTTPHEADERLEN_Ibp_Server_Node ) ;
	if( HTTPHEADER_Ibp_Server_Node == NULL )
	{
		ERRORLOGSG( "HTTP HEADER[%s] not exist" , IBP_HTTPHEADER_IBP_SERVER_NODE );
		return HTTP_BAD_REQUEST;
	}
	
	p_node = IBMAGetThisNodePtr( p_env->ibma_config_space ) ;
	p_env->p_this_node_unit = IBMAQueryNode( p_env->ibma_config_space , p_node ) ;
	if( p_env->p_this_node_unit == NULL )
	{
		ERRORLOGSG( "this node not exist" );
		return HTTP_INTERNAL_SERVER_ERROR;
	}
	else
	{
		DEBUGLOGSG( "server node[%.*s] found" , HTTPHEADERLEN_Ibp_Server_Node , HTTPHEADER_Ibp_Server_Node );
	}
	
	node_len = strlen(p_node) ;
	if( HTTPHEADERLEN_Ibp_Server_Node != node_len || MEMCMP( HTTPHEADER_Ibp_Server_Node , != , p_node , node_len ) )
	{
		ERRORLOGSG( "server node[%.*s] is not this node[%s]" , HTTPHEADERLEN_Ibp_Server_Node , HTTPHEADER_Ibp_Server_Node , p_node );
		return HTTP_NOT_FOUND;
	}
	
	HTTPHEADER_Ibp_Client_Node = QueryHttpHeaderPtr( p_env->accepted_session.http , IBP_HTTPHEADER_IBP_CLIENT_NODE , & HTTPHEADERLEN_Ibp_Client_Node ) ;
	if( HTTPHEADER_Ibp_Client_Node == NULL )
	{
		ERRORLOGSG( "HTTP HEADER[%s] not exist" , IBP_HTTPHEADER_IBP_CLIENT_NODE );
		return HTTP_BAD_REQUEST;
	}
	
	memset( node , 0x00 , sizeof(node) );
	strncpy( node , HTTPHEADER_Ibp_Client_Node , MIN(HTTPHEADERLEN_Ibp_Client_Node,sizeof(node)-1) );
	p_env->p_client_node_unit = IBMAQueryNode( p_env->ibma_config_space , node ) ;
	if( p_env->p_client_node_unit == NULL )
	{
		ERRORLOGSG( "client node[%s] not exist" , node );
		return HTTP_INTERNAL_SERVER_ERROR;
	}
	else
	{
		DEBUGLOGSG( "client node[%.*s] found" , HTTPHEADERLEN_Ibp_Client_Node , HTTPHEADER_Ibp_Client_Node );
	}
	
	p_env->p_client_host_unit = IBMATravelNodeHosts( p_env->ibma_config_space , p_env->p_client_node_unit , NULL ) ;
	while( p_env->p_client_host_unit )
	{
		if( STRCMP( p_env->accepted_session.netaddr.ip , == , IBMAGetHostIpPtr(p_env->p_client_host_unit) ) )
			break;
		
		p_env->p_client_host_unit = IBMATravelNodeHosts( p_env->ibma_config_space , p_env->p_client_node_unit , p_env->p_client_host_unit ) ;
	}
	if( p_env->p_client_host_unit == NULL )
	{
		ERRORLOGSG( "client host ip[%s] not config in node[%s]" , p_env->accepted_session.netaddr.ip , node );
		return HTTP_INTERNAL_SERVER_ERROR;
	}
	else
	{
		DEBUGLOGSG( "client host ip[%s] config in node[%s]" , p_env->accepted_session.netaddr.ip , node );
	}
	
	return HTTP_OK;
}

static int CheckHeaderApp( struct IbasEnv *p_env )
{
	char			*HTTPHEADER_Ibp_App_Code = NULL ;
	int			HTTPHEADERLEN_Ibp_App_Code ;
	char			app[ IBP_MAXLEN_APP + 1 ] ;
	
	HTTPHEADER_Ibp_App_Code = QueryHttpHeaderPtr( p_env->accepted_session.http , IBP_HTTPHEADER_IBP_APP_CODE , & HTTPHEADERLEN_Ibp_App_Code ) ;
	if( HTTPHEADER_Ibp_App_Code == NULL )
	{
		ERRORLOGSG( "HTTP HEADER[%s] not exist" , IBP_HTTPHEADER_IBP_APP_CODE );
		return HTTP_BAD_REQUEST;
	}
	
	memset( app , 0x00 , sizeof(app) );
	strncpy( app , HTTPHEADER_Ibp_App_Code , MIN(HTTPHEADERLEN_Ibp_App_Code,sizeof(app)-1) );
	p_env->p_this_app_unit = IBMAQueryApp( p_env->ibma_config_space , app ) ;
	if( p_env->p_this_app_unit == NULL )
	{
		ERRORLOGSG( "app[%s] not exist" , app );
		return HTTP_NOT_FOUND;
	}
	else
	{
		DEBUGLOGSG( "app[%s] found" , app );
	}
	
	return HTTP_OK;
}

static int OnCallPreTransaction( struct IbasEnv *p_env )
{
	int			nret = 0 ;
	
	nret = CheckHeaderNode( p_env ) ;
	if( nret != HTTP_OK )
	{
		ERRORLOGSG( "CheckHeaderNode failed[%d]" , nret );
		return nret;
	}
	
	nret = CheckHeaderApp( p_env ) ;
	if( nret != HTTP_OK )
	{
		ERRORLOGSG( "CheckHeaderApp failed[%d]" , nret );
		return nret;
	}
	
	nret = ReloadRsaKey( p_env->accepted_session.http_secure_env , p_env->p_this_node_unit , p_env->p_client_node_unit ) ;
	if( nret )
	{
		ERRORLOGSG( "ReloadRsaKeyFiles[%s][%s] failed[%d]" , p_env->p_this_node_unit->node , p_env->p_client_node_unit->node , nret );
		return HTTP_INTERNAL_SERVER_ERROR;
	}
	
	nret = FormatHttpResponseStartLine( HTTP_OK , p_env->accepted_session.http , 1
		, IBP_HTTPHEADER_IBP_TRANS_TIMEOUT ": %d" HTTP_RETURN_NEWLINE
		HTTP_RETURN_NEWLINE
		, p_env->p_this_app_unit->timeout ) ;
	if( nret )
	{
		ERRORLOGSG( "FormatHttpResponseStartLine failed[%d]" , nret );
		return HTTP_INTERNAL_SERVER_ERROR;
	}
	
	return HTTP_OK;
}

static int OnCallTransaction( struct IbasEnv *p_env )
{
	struct SoFile		so_file ;
	
	struct sigaction	action ;
	
	int			nret = 0 ;
	int			somain_nret = 0 ;
	
	nret = CheckHeaderNode( p_env ) ;
	if( nret != HTTP_OK )
	{
		ERRORLOGSG( "CheckHeaderNode failed[%d]" , nret );
		return nret;
	}
	
	nret = CheckHeaderApp( p_env ) ;
	if( nret != HTTP_OK )
	{
		ERRORLOGSG( "CheckHeaderApp failed[%d]" , nret );
		return nret;
	}
	
	nret = ReloadRsaKey( p_env->accepted_session.http_secure_env , p_env->p_this_node_unit , p_env->p_client_node_unit ) ;
	if( nret )
	{
		ERRORLOGSG( "ReloadRsaKeyFiles[%s][%s] failed[%d]" , p_env->p_this_node_unit->node , p_env->p_client_node_unit->node , nret );
		return HTTP_INTERNAL_SERVER_ERROR;
	}
	
	strcpy( p_env->p_worker_detail->processing_info.node , p_env->p_client_node_unit->node );
	strcpy( p_env->p_worker_detail->processing_info.ip , p_env->p_client_host_unit->ip );
	strcpy( p_env->p_worker_detail->processing_info.app , p_env->p_this_app_unit->app );
	if( p_env->p_this_app_unit->timeout2 > 0 )
		p_env->p_worker_detail->processing_info.timeout = p_env->p_this_app_unit->timeout2 ;
	else
		p_env->p_worker_detail->processing_info.timeout = p_env->p_this_app_unit->timeout ;
	
	memset( & so_file , 0x00 , sizeof(struct SoFile) );
	strcpy( so_file.bin , p_env->p_this_app_unit->bin );
	p_env->p_this_so_file = QuerySoBinTreeNode( p_env , & so_file ) ;
	DEBUGLOGSG( "QuerySoBinTreeNode[%s] return[%p] - so_cache_count[%d] max_so_cache_count[%d]" , p_env->p_this_app_unit->bin , p_env->p_this_so_file , p_env->so_cache_count , p_env->ibas_conf.ibas.app.max_so_cache_count );
	if( p_env->p_this_so_file == NULL )
	{
		char			*path = NULL ;
		
		if( p_env->so_cache_count+1 > p_env->ibas_conf.ibas.app.max_so_cache_count )
		{
			UnlinkMinSoCallCountTreeNode( p_env );
			DEBUGLOGSG( "UnlinkMinSoCallCountTreeNode ok" );
			p_env->so_cache_count--;
		}
		
		p_env->p_this_so_file = (struct SoFile *)malloc( sizeof(struct SoFile) ) ;
		if( p_env->p_this_so_file == NULL )
		{
			ERRORLOGSG( "malloc failed , errno[%d]" , errno );
			return HTTP_INTERNAL_SERVER_ERROR;
		}
		memset( p_env->p_this_so_file , 0x00 , sizeof(struct SoFile) );
		
		path = getenv("IBAS_SO_PATH") ;
		if( path )
			snprintf( p_env->p_this_so_file->so_pathfilename , sizeof(p_env->p_this_so_file->so_pathfilename)-1 , "%s/%s" , path , p_env->p_this_app_unit->bin );
		else
			snprintf( p_env->p_this_so_file->so_pathfilename , sizeof(p_env->p_this_so_file->so_pathfilename)-1 , "%s/so/%s" , getenv("HOME") , p_env->p_this_app_unit->bin );
		strcpy( p_env->p_this_so_file->bin , p_env->p_this_app_unit->bin );
		p_env->p_this_so_file->call_count = 0 ;
		
		p_env->p_this_so_file->so_handle = dlopen( p_env->p_this_so_file->so_pathfilename , RTLD_NOW ) ;
		if( p_env->p_this_so_file->so_handle == NULL )
		{
			ERRORLOGSG( "dlopen[%s] failed , dlerror[%s]" , p_env->p_this_so_file->so_pathfilename , dlerror() );
			free( p_env->p_this_so_file );
			return HTTP_INTERNAL_SERVER_ERROR;
		}
		else
		{
			DEBUGLOGSG( "dlopen[%s] ok" , p_env->p_this_so_file->so_pathfilename );
		}
		
		p_env->p_this_so_file->pfuncIbasSomain = dlsym( p_env->p_this_so_file->so_handle , IBAS_SOMAIN ) ;
		if( p_env->p_this_so_file->pfuncIbasSomain == NULL )
		{
			ERRORLOGSG( "dlsym[%s][%s] failed , dlerror[%s]" , p_env->p_this_so_file->so_pathfilename , IBAS_SOMAIN , dlerror() );
			dlclose( p_env->p_this_so_file->so_handle );
			free( p_env->p_this_so_file );
			return HTTP_INTERNAL_SERVER_ERROR;
		}
		else
		{
			DEBUGLOGSG( "dlsym[%s][%s] ok" , p_env->p_this_so_file->so_pathfilename , IBAS_SOMAIN );
		}
		
		p_env->p_this_so_file->file_wd = inotify_add_watch( p_env->inotify_fd , p_env->p_this_so_file->so_pathfilename , IN_ATTRIB|IN_CLOSE_WRITE|IN_CREATE|IN_DELETE|IN_DELETE_SELF|IN_MODIFY|IN_MOVE_SELF|IN_MOVED_FROM|IN_MOVED_TO|IN_IGNORED ) ;
		if( p_env->p_this_so_file->file_wd == -1 )
		{
			ERRORLOGSG( "inotify_add_watch[%s] failed , errno[%d]" , p_env->p_this_so_file->so_pathfilename , errno );
			dlclose( p_env->p_this_so_file->so_handle );
			free( p_env->p_this_so_file );
			return HTTP_INTERNAL_SERVER_ERROR;
		}
		else
		{
			DEBUGLOGSG( "inotify_add_watch[%s] ok[%d]" , p_env->p_this_so_file->so_pathfilename , p_env->p_this_so_file->file_wd );
		}
		
		nret = LinkSoBinTreeNode( p_env , p_env->p_this_so_file ) ;
		if( nret )
		{
			ERRORLOGSG( "LinkSoBinTreeNode[%s] failed[%d] , errno[%d]" , p_env->p_this_so_file->bin , nret , errno );
			dlclose( p_env->p_this_so_file->so_handle );
			free( p_env->p_this_so_file );
			return HTTP_INTERNAL_SERVER_ERROR;
		}
		else
		{
			DEBUGLOGSG( "LinkSoBinTreeNode[%s] ok" , p_env->p_this_so_file->bin );
		}
		
		nret = LinkSoCallCountTreeNode( p_env , p_env->p_this_so_file ) ;
		if( nret )
		{
			ERRORLOGSG( "LinkSoCallCountTreeNode failed[%d] , errno[%d]" , nret , errno );
			UnlinkSoBinTreeNode( p_env , p_env->p_this_so_file );
			dlclose( p_env->p_this_so_file->so_handle );
			free( p_env->p_this_so_file );
			return HTTP_INTERNAL_SERVER_ERROR;
		}
		else
		{
			DEBUGLOGSG( "LinkSoCallCountTreeNode ok" );
		}
		
		nret = LinkSoFileWdTreeNode( p_env , p_env->p_this_so_file ) ;
		if( nret )
		{
			ERRORLOGSG( "LinkSoFileWdTreeNode failed[%d] , errno[%d]" , nret , errno );
			UnlinkSoBinTreeNode( p_env , p_env->p_this_so_file );
			UnlinkSoCallCountTreeNode( p_env , p_env->p_this_so_file );
			dlclose( p_env->p_this_so_file->so_handle );
			free( p_env->p_this_so_file );
			return HTTP_INTERNAL_SERVER_ERROR;
		}
		else
		{
			DEBUGLOGSG( "LinkSoFileWdTreeNode ok" );
		}
		
		p_env->so_cache_count++;
	}
	
	nret = FormatHttpResponseStartLine( HTTP_OK , p_env->accepted_session.http , 0 , NULL ) ;
	if( nret )
	{
		ERRORLOGSG( "FormatHttpResponseStartLine failed[%d]" , nret );
		UnlinkSoBinTreeNode( p_env , p_env->p_this_so_file );
		dlclose( p_env->p_this_so_file->so_handle );
		free( p_env->p_this_so_file );
		return HTTP_INTERNAL_SERVER_ERROR;
	}
	
	nret = BeforeCallSomain( p_env ) ;
	if( nret )
	{
		ERRORLOGSG( "BeforeCallSomain failed[%d]" , nret );
		return nret;
	}
	
	IBPChangeAppLogFilename( p_env->ibas_conf.ibas.log.app_output , p_env->p_this_app_unit->app );
	IBPChangeAppLogLevel( IBPConvertLogLevel(p_env->ibas_conf.ibas.log.app_loglevel) );
	
	memset( & action , 0x00 , sizeof(struct sigaction) );
	action.sa_sigaction = app_signal_handler ;
	action.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART ;
	sigaction( SIGSEGV , & action , NULL );
	sigaction( SIGFPE , & action , NULL );
	sigaction( SIGILL , & action , NULL );
	sigaction( SIGBUS , & action , NULL );
	sigaction( SIGABRT , & action , NULL );
	sigaction( SIGSYS , & action , NULL );
	if( p_env->p_this_app_unit->timeout2 > 0 )
	{
		alarm( p_env->p_this_app_unit->timeout2 );
		DEBUGLOGSG( "alarm [%d]seconds" , p_env->p_this_app_unit->timeout2 );
	}
	else
	{
		int		timeout = p_env->p_this_app_unit->timeout + p_env->p_this_app_unit->timeout / 2 ;
		alarm( timeout );
		DEBUGLOGSG( "alarm [%d]seconds" , timeout );
	}
	sigaction( SIGALRM , & action , NULL );
	
	somain_nret = p_env->p_this_so_file->pfuncIbasSomain( p_env->accepted_session.req_body , p_env->accepted_session.rsp_body , & (p_env->p_worker_detail->processing_info.addon_files) ) ;
	
	alarm( 0 );
	signal( SIGALRM , SIG_DFL );
	signal( SIGSEGV , SIG_DFL );
	signal( SIGFPE , SIG_DFL );
	signal( SIGILL , SIG_DFL );
	signal( SIGBUS , SIG_DFL );
	signal( SIGABRT , SIG_DFL );
	signal( SIGSYS , SIG_DFL );
	
	IBPChangeAppLogFilename( p_env->ibas_conf.ibas.log.worker_output , p_env->p_worker_detail->index );
	
	p_env->p_this_so_file->call_count++;
	nret = UpdateSoCallCountTreeNode( p_env , p_env->p_this_so_file ) ;
	if( nret )
	{
		ERRORLOGSG( "UpdateSoCallCountTreeNode failed , errno[%d]" , errno );
		UnlinkSoBinTreeNode( p_env , p_env->p_this_so_file );
		UnlinkSoCallCountTreeNode( p_env , p_env->p_this_so_file );
		UnlinkSoFileWdTreeNode( p_env , p_env->p_this_so_file );
		dlclose( p_env->p_this_so_file->so_handle );
		free( p_env->p_this_so_file );
		p_env->so_cache_count--;
		return HTTP_INTERNAL_SERVER_ERROR;
	}
	
	if( somain_nret )
		return HTTP_SERVICE_UNAVAILABLE;
	
	if( p_env->accepted_session.response_flag == 0 )
	{
		nret = AfterCallSomain( p_env ) ;
		if( nret )
		{
			ERRORLOGSG( "AfterCallSomain failed[%d]" , nret );
			return nret;
		}
	}
	
	return HTTP_OK;
}

static int OnCallPutFile( struct IbasEnv *p_env )
{
	char		*p_filename = NULL ;
	int		filename_len ;
	char		file_id[ IBP_MAXLEN_FILENAME + 1 ] ;
	int		file_len ;
	char		filename[ IBP_MAXLEN_FILENAME + 1 ] ;
	char		pathfilename[ IBP_MAXLEN_FILENAME + 1 ] ;
	FILE		*fp = NULL ;
	
	int		nret = 0 ;
	
	nret = CheckHeaderNode( p_env ) ;
	if( nret != HTTP_OK )
	{
		ERRORLOGSG( "CheckHeaderNode failed[%d]" , nret );
		return nret;
	}
	
	nret = ReloadRsaKey( p_env->accepted_session.http_secure_env , p_env->p_this_node_unit , p_env->p_client_node_unit ) ;
	if( nret )
	{
		ERRORLOGSG( "ReloadRsaKeyFiles[%s][%s] failed[%d]" , p_env->p_this_node_unit->node , p_env->p_client_node_unit->node , nret );
		return HTTP_INTERNAL_SERVER_ERROR;
	}
	
	p_filename = QueryHttpHeaderPtr( p_env->accepted_session.http , IBP_HTTPHEADER_IBP_FILE_NAME , & filename_len ) ;
	if( p_filename == NULL )
	{
		ERRORLOGSG( "QueryHttpHeaderPtr[%s] not found" , IBP_HTTPHEADER_IBP_FILE_NAME );
		return HTTP_BAD_REQUEST;
	}
	memset( file_id , 0x00 , sizeof(file_id) );
	snprintf( file_id , sizeof(file_id)-1 , "%.*s" , filename_len , p_filename );
	TrimFileId( file_id );
	
	memset( filename , 0x00 , sizeof(filename) );
	memset( pathfilename , 0x00 , sizeof(pathfilename) );
	fp = IBPCreateTempFile( file_id , filename , pathfilename , "wb" ) ;
	if( fp == NULL )
	{
		ERRORLOGSG( "CreateTempFile[%s] failed , errno[%d]" , file_id , errno );
		return HTTP_INTERNAL_SERVER_ERROR;
	}
	else
	{
		INFOLOGSG( "CreateTempFile[%s] ok , filename[%s] pathfilename[%s]" , file_id , filename , pathfilename );
	}
	fclose( fp );
	
	nret = ExtractFileFromHttpBuffer( p_env->accepted_session.http , GetHttpRequestBuffer(p_env->accepted_session.http) , p_env->accepted_session.http_secure_env , pathfilename , & file_len ) ;
	if( nret )
	{
		ERRORLOGSG( "ExtractFileFromHttpBuffer[%s] [%d]bytes failed , errno[%d]" , pathfilename , file_len , errno );
		return HTTP_INTERNAL_SERVER_ERROR;
	}
	else
	{
		INFOLOGSG( "ExtractFileFromHttpBuffer[%s] [%d]bytes ok" , pathfilename , file_len );
	}
	
	nret = FormatHttpResponseStartLine( HTTP_OK , p_env->accepted_session.http , 0
		, "%s: %s" HTTP_RETURN_NEWLINE
		HTTP_RETURN_NEWLINE
		, IBP_HTTPHEADER_IBP_FILE_NAME , filename ) ;
	if( nret )
	{
		ERRORLOGSG( "FormatHttpResponseStartLine failed[%d]" , nret );
		return HTTP_INTERNAL_SERVER_ERROR;
	}
	
	return HTTP_OK;
}

static int OnCallGetFile( struct IbasEnv *p_env )
{
	char			*filename = NULL ;
	int			filename_len ;
	char			pathfilename[ IBP_MAXLEN_FILENAME + 1 ] ;
	int			file_len ;
	
	int			nret = 0 ;
	
	nret = CheckHeaderNode( p_env ) ;
	if( nret != HTTP_OK )
	{
		ERRORLOGSG( "CheckHeaderNode failed[%d]" , nret );
		return nret;
	}
	
	nret = ReloadRsaKey( p_env->accepted_session.http_secure_env , p_env->p_this_node_unit , p_env->p_client_node_unit ) ;
	if( nret )
	{
		ERRORLOGSG( "ReloadRsaKeyFiles[%s][%s] failed[%d]" , p_env->p_this_node_unit->node , p_env->p_client_node_unit->node , nret );
		return HTTP_INTERNAL_SERVER_ERROR;
	}
	
	filename = QueryHttpHeaderPtr( p_env->accepted_session.http , IBP_HTTPHEADER_IBP_FILE_NAME , & filename_len ) ;
	if( filename == NULL )
	{
		ERRORLOGSG( "no http header[%s]" , IBP_HTTPHEADER_IBP_FILE_NAME );
		return HTTP_BAD_REQUEST;
	}
	
	nret = FormatHttpResponseStartLine( HTTP_OK , p_env->accepted_session.http , 0 , NULL ) ;
	if( nret )
	{
		ERRORLOGSG( "FormatHttpResponseStartLine failed[%d]" , nret );
		return HTTP_INTERNAL_SERVER_ERROR;
	}
	
	memset( pathfilename , 0x00 , sizeof(pathfilename) );
	snprintf( pathfilename , sizeof(pathfilename)-1 , "%s/file/%.*s" , getenv("HOME") , filename_len , filename );
	nret = PutFileToHttpBuffer( p_env->accepted_session.http , GetHttpResponseBuffer(p_env->accepted_session.http) , p_env->accepted_session.http_secure_env , pathfilename , & file_len ) ;
	if( nret )
	{
		ERRORLOGSG( "PutFileToHttpBuffer[%s] failed[%d]" , pathfilename , nret );
		return HTTP_INTERNAL_SERVER_ERROR;
	}
	else
	{
		INFOLOGSG( "PutFileToHttpBuffer[%s] ok , file_len[%d]" , pathfilename , file_len );
	}
	
	return HTTP_OK;
}

int OnDispatchUri( struct IbasEnv *p_env )
{
	char			*HTTPHEADER_Uri = NULL ;
	int			HTTPHEADERLEN_Uri ;
	
	char			*HTTPHEADER_Ibp_Trans_Timeout = NULL ;
	int			HTTPHEADERLEN_Ibp_Trans_Timeout ;
	
	int			nret = 0 ;
	
	HTTPHEADER_Uri = GetHttpHeaderPtr_URI( p_env->accepted_session.http , & HTTPHEADERLEN_Uri ) ;
	if( HTTPHEADER_Uri == NULL )
	{
		ERRORLOGSG( "HTTP URI not exist" );
		return HTTP_INTERNAL_SERVER_ERROR;
	}
	
	if( HTTPHEADERLEN_Uri == sizeof(IBP_URI_PRE_TRANSACTION)-1 && STRNICMP( HTTPHEADER_Uri , == , IBP_URI_PRE_TRANSACTION , sizeof(IBP_URI_PRE_TRANSACTION)-1 ) )
	{
		nret = OnCallPreTransaction( p_env ) ;
		if( nret != HTTP_OK )
		{
			ERRORLOGSG( "OnCallPreTransaction failed[%d]" , nret );
			return nret;
		}
		else
		{
			INFOLOGSG( "OnCallPreTransaction ok" );
		}
	}
	else if( HTTPHEADERLEN_Uri == sizeof(IBP_URI_TRANSACTION)-1 && STRNICMP( HTTPHEADER_Uri , == , IBP_URI_TRANSACTION , sizeof(IBP_URI_TRANSACTION)-1 ) )
	{
		p_env->p_worker_detail->processing_info.output_event_flag = 1 ;
		
		nret = OnCallTransaction( p_env ) ;
		if( nret != HTTP_OK )
		{
			ERRORLOGSG( "OnCallTransaction failed[%d]" , nret );
			return nret;
		}
		else
		{
			INFOLOGSG( "OnCallTransaction ok" );
		}
	}
	else if( HTTPHEADERLEN_Uri == sizeof(IBP_URI_PUT_FILE)-1 && STRNICMP( HTTPHEADER_Uri , == , IBP_URI_PUT_FILE , sizeof(IBP_URI_PUT_FILE)-1 ) )
	{
		nret = OnCallPutFile( p_env ) ;
		if( nret != HTTP_OK )
		{
			ERRORLOGSG( "OnCallPutFile failed[%d]" , nret );
			return nret;
		}
		else
		{
			INFOLOGSG( "OnCallPutFile ok" );
		}
	}
	else if( HTTPHEADERLEN_Uri == sizeof(IBP_URI_GET_FILE)-1 && STRNICMP( HTTPHEADER_Uri , == , IBP_URI_GET_FILE , sizeof(IBP_URI_GET_FILE)-1 ) )
	{
		nret = OnCallGetFile( p_env ) ;
		if( nret != HTTP_OK )
		{
			ERRORLOGSG( "OnCallGetFile failed[%d]" , nret );
			return nret;
		}
		else
		{
			INFOLOGSG( "OnCallGetFile ok" );
		}
	}
	else if( HTTPHEADERLEN_Uri == sizeof(IBP_URI_NULL)-1 && STRNICMP( HTTPHEADER_Uri , == , IBP_URI_NULL , sizeof(IBP_URI_NULL)-1 ) )
	{
		nret = FormatHttpResponseStartLine( HTTP_OK , p_env->accepted_session.http , 1 , HTTP_RETURN_NEWLINE ) ;
		if( nret )
		{
			ERRORLOGSG( "FormatHttpResponseStartLine failed[%d]" , nret );
			return HTTP_INTERNAL_SERVER_ERROR;
		}
	}
	else if( HTTPHEADERLEN_Uri == sizeof(URI_SHOW_STATUS)-1 && STRNICMP( HTTPHEADER_Uri , == , URI_SHOW_STATUS , sizeof(URI_SHOW_STATUS)-1 ) )
	{
		char		body[ 4096 + 1 ] ;
		
		memset( body , 0x00 , sizeof(body) );
		snprintf( body , sizeof(body)-1 , "this_node[%s] run_status[%s] service_listen[%s:%d]\n"
						"nodes_count[%d] app_count[%d]\n"
						"worker_space[%d][0x%X][%d] accept_mutex[%d][0x%X][%d]\n"
						, p_env->node , (g_EXIT_flag==0?"RUNNING":"EXITING") , p_env->listen_session.netaddr.ip , p_env->listen_session.netaddr.port
						, IBMAGetNodeCount(p_env->ibma_config_space) , IBMAGetAppCount(p_env->ibma_config_space)
						, p_env->workers_space.shm.proj_id , p_env->workers_space.shm.shmkey , p_env->workers_space.shm.shmid , p_env->accept_mutex.sem.proj_id , p_env->accept_mutex.sem.semkey , p_env->accept_mutex.sem.semid );
		
		nret = FormatHttpResponseStartLine( HTTP_OK , p_env->accepted_session.http , 0 , NULL ) ;
		if( nret )
		{
			ERRORLOGSG( "FormatHttpResponseStartLine failed[%d]" , nret );
			return HTTP_INTERNAL_SERVER_ERROR;
		}
		
		nret = StrcatfHttpBuffer( GetHttpResponseBuffer(p_env->accepted_session.http) , "Content-length: %d" HTTP_RETURN_NEWLINE
												HTTP_RETURN_NEWLINE
												"%s"
												, strlen(body)
												, body ) ;
		if( nret )
		{
			ERRORLOGSG( "StrcatfHttpBuffer failed[%d]" , nret );
			return HTTP_INTERNAL_SERVER_ERROR;
		}
	}
	else if( HTTPHEADERLEN_Uri == sizeof(URI_SHOW_BBSTAT)-1 && STRNICMP( HTTPHEADER_Uri , == , URI_SHOW_BBSTAT , sizeof(URI_SHOW_BBSTAT)-1 ) )
	{
		char		body[ 4096 + 1 ] ;
		
		memset( body , 0x00 , sizeof(body) );
		snprintf( body , sizeof(body)-1 , "initing[%d] idle[%d] listening[%d] working[%d] keepalive[%d] restarting[%d] exiting[%d]\n"
						, p_env->workers_space.workers_stat->initing_count , p_env->workers_space.workers_stat->idle_count , p_env->workers_space.workers_stat->listening_count , p_env->workers_space.workers_stat->working_count , p_env->workers_space.workers_stat->keepalive_count , p_env->workers_space.workers_stat->restarting_count , p_env->workers_space.workers_stat->exiting_count );
		
		nret = FormatHttpResponseStartLine( HTTP_OK , p_env->accepted_session.http , 0 , NULL ) ;
		if( nret )
		{
			ERRORLOGSG( "FormatHttpResponseStartLine failed[%d]" , nret );
			return HTTP_INTERNAL_SERVER_ERROR;
		}
		
		nret = StrcatfHttpBuffer( GetHttpResponseBuffer(p_env->accepted_session.http) , "Content-length: %d" HTTP_RETURN_NEWLINE
												HTTP_RETURN_NEWLINE
												"%s"
												, strlen(body)
												, body ) ;
		if( nret )
		{
			ERRORLOGSG( "StrcatfHttpBuffer failed[%d]" , nret );
			return HTTP_INTERNAL_SERVER_ERROR;
		}
	}
	else if( HTTPHEADERLEN_Uri == sizeof(URI_SHOW_BBDETAIL)-1 && STRNICMP( HTTPHEADER_Uri , == , URI_SHOW_BBDETAIL , sizeof(URI_SHOW_BBDETAIL)-1 ) )
	{
		char			body[ 4096 + 1 ] ;
		time_t			tt ;
		int			index ;
		struct IbasWorkerDetail	*p_worker_detail = NULL ;
		
		tt = time(NULL) ;
		
		memset( body , 0x00 , sizeof(body) );
		snprintf( body+strlen(body) , sizeof(body)-1-strlen(body) , "%-5s %-10s %-19s %8s/%-8s %-16s %-8s %-10s %-10s\n" , "index" , "pid" , "begin_timestamp" , "elapse" , "timeout" , "app" , "procount" , "status" , "cmd" );
		snprintf( body+strlen(body) , sizeof(body)-1-strlen(body) , "-----------------------------------------------------------------------------------------------\n" );
		for( index = 0 , p_worker_detail = p_env->workers_space.worker_detail_array ; index < p_env->ibas_conf.ibas.mpm.max_count ; index++ , p_worker_detail++ )
		{
			if( p_worker_detail->status )
			{
				char	buf[ 8 + 1 + 8 + 1 ] ;
				
				memset( buf , 0x00 , sizeof(buf) );
				if( p_worker_detail->processing_info.timeval_stat.receiving_request.tv_sec > 0 )
				{
					snprintf( buf , sizeof(buf)-1 , "%8d/%-8d" , (int)(tt-p_worker_detail->processing_info.timeval_stat.receiving_request.tv_sec) , p_worker_detail->processing_info.timeout );
				}
				
				snprintf( body+strlen(body) , sizeof(body)-1-strlen(body) , "%-5d %-10d %-19s %-17s %-16s %-8d %-10s %-10s\n"
											, p_worker_detail->index
											, p_worker_detail->pid
											, p_worker_detail->processing_info.timeval_stat.timestamp_str
											, buf
											, p_worker_detail->processing_info.app
											, p_worker_detail->process_count
											, GetWorkerStatus(p_worker_detail->status)
											, GetWorkerStatus(p_worker_detail->cmd) );
			}
		}
		
		nret = FormatHttpResponseStartLine( HTTP_OK , p_env->accepted_session.http , 0 , NULL ) ;
		if( nret )
		{
			ERRORLOGSG( "FormatHttpResponseStartLine failed[%d]" , nret );
			return HTTP_INTERNAL_SERVER_ERROR;
		}
		
		nret = StrcatfHttpBuffer( GetHttpResponseBuffer(p_env->accepted_session.http) , "Content-length: %d" HTTP_RETURN_NEWLINE
												HTTP_RETURN_NEWLINE
												"%s"
												, strlen(body)
												, body ) ;
		if( nret )
		{
			ERRORLOGSG( "StrcatfHttpBuffer failed[%d]" , nret );
			return HTTP_INTERNAL_SERVER_ERROR;
		}
	}
	
	HTTPHEADER_Ibp_Trans_Timeout = QueryHttpHeaderPtr( p_env->accepted_session.http , IBP_HTTPHEADER_IBP_TRANS_TIMEOUT , & HTTPHEADERLEN_Ibp_Trans_Timeout ) ;
	if( HTTPHEADER_Ibp_Trans_Timeout )
	{
		p_env->p_worker_detail->next_timeout = nstoi( HTTPHEADER_Ibp_Trans_Timeout , HTTPHEADERLEN_Ibp_Trans_Timeout ) ;
	}
	
	return HTTP_OK;
}

